#! /usr/bin/env python
###
# -*- mode: python -*-
###
#
# (c) 2000-2007 Wijnand Modderman <wijnand at tehmaze dot com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
# basic configure script
###

__revision__ = '$Hg$'

import os
import sys
import tempfile
import urllib
import zlib
import zipfile
import popen2
import glob

from ddb.settings import *

SF_MIRROR='belnet'
HOME_BASE=os.getcwd() + os.path.sep
INSTALL_OPTS='--install-purelib=%slib --install-platlib=%slib --install-scripts=%sother --install-data=%sdata' % \
    tuple([HOME_BASE] * 4)

PACKAGES={
    # for core
    'pysqlite2': {
        'src': 'http://initd.org/pub/software/pysqlite/releases/2.3/2.3.2/pysqlite-2.3.2.tar.gz',
        'deb': 'python-pysqlite2',
        'rpm': 'pyton-sqlite',
        'pac': 'extra/python-pysqlite'
    },
    'twisted': {
        'src': 'http://tmrc.mit.edu/mirror/twisted/Twisted/2.4/Twisted-2.4.0.tar.bz2',
        'deb': 'python2.4-twisted',
        'rpm': 'python-twisted',
        'pac': 'extra/twisted'
    },
    # for RSS
    'feedparser': {
        'src': 'http://%s.dl.sourceforge.net/feedparser/feedparser-4.1.zip' % SF_MIRROR
    },
    'OpenSSL': {
        'src': 'http://%s.dl.sourceforge.net/pyopenssl/pyOpenSSL-0.6.tar.gz' % SF_MIRROR
    },
}

sys.path.append(HOME_BASE + 'lib')

class unzip:
    def __init__(self, verbose = False, percent = 10):
        self.verbose = verbose
        self.percent = percent
        
    def extract(self, file, dir):
        if not dir.endswith(':') and not os.path.exists(dir):
            os.mkdir(dir)

        zf = zipfile.ZipFile(file)

        # create directory structure to house files
        self._createstructure(file, dir)

        num_files = len(zf.namelist())
        percent = self.percent
        divisions = 100 / percent
        perc = int(num_files / divisions)

        # extract files to directory structure
        for i, name in enumerate(zf.namelist()):

            if self.verbose == True:
                print "(unzip) extracting %s" % name
            elif perc > 0 and (i % perc) == 0 and i > 0:
                complete = int (i / perc) * percent
                print "(unzip) %s%% complete" % complete

            if not name.endswith('/'):
                outfile = open(os.path.join(dir, name), 'wb')
                outfile.write(zf.read(name))
                outfile.flush()
                outfile.close()


    def _createstructure(self, file, dir):
        self._makedirs(self._listdirs(file), dir)


    def _makedirs(self, directories, basedir):
        """ Create any directories that don't currently exist """
        for dir in directories:
            curdir = os.path.join(basedir, dir)
            if not os.path.exists(curdir):
                os.mkdir(curdir)

    def _listdirs(self, file):
        """ Grabs all the directories in the zip structure
        This is necessary to create the structure before trying
        to extract the file to it. """
        zf = zipfile.ZipFile(file)

        dirs = []

        for name in zf.namelist():
            if name.endswith('/'):
                dirs.append(name)

        dirs.sort()
        return dirs

def echo(txt):
    sys.stdout.write(txt)
    sys.stdout.flush()

def doShell(cmnd):
    print 'executing `%s`' % cmnd
    r,w,e = popen2.popen3(cmnd)
    _e = e.readlines()
    e.close()
    if _e:
        w.close()
        r.close()
        print 'error running "%s":' % cmnd
        print ''.join(_e)
        sys.exit(1)
    _r = r.readlines()
    r.close()
    w.close()
    if _r:
        print ''.join(_r)
    else:
        print 'ran "%s", but no output was generated' % cmnd

def doSetup(directory):
    old = os.getcwd()
    os.chdir(directory)
    doShell('python setup.py build')
    doShell('python setup.py install %s' % INSTALL_OPTS)
    os.chdir(old)

def findSetup(directory):
    print 'looking for setup.py in %s' % directory
    files = glob.glob('%s/*' % directory)
    if 'setup.py' in [os.path.basename(x) for x in files]:
        return directory
    elif not files:
        return None
    else:
        dirs = []
        for file in files:
            if os.path.isdir(file):
                dirs.append(file)
        if not dirs:
            return None
        else:
            for dir in dirs:
                setup = findSetup(dir)
                if setup:
                    return setup
            return None

def doInstall(url):
    #temp = tempfile.mkdtemp(os.path.basename(url))
    old  = os.getcwd()
    file = os.path.basename(url)
    name = file.split('.')[0]
    temp = 'tmp'
    if not os.path.isfile(temp + os.path.sep + file):
        os.chdir(temp)
        echo('fetching %s ... ' % url)
        try:
            data = urllib.urlopen(url).read()
        except Exception, e:
            print 'failed: %s' % str(e)
            sys.exit(1)
        print 'done, %d bytes' % len(data)
        echo('saving %s ... ' % file)
        fh   = open(file, 'w')
        fh.write(data)
        fh.close()
        os.chdir(old)
    if os.path.isfile(temp + os.path.sep + file):
        print 'ok'
    else:
        print 'failed!'
        sys.exit(1)
    if file.lower().endswith('.zip'):
        print 'extracting %s:' % file
        unzipper = unzip(True)
        unzipper.extract(temp + os.path.sep + file, temp + os.path.sep + name)
    elif file.lower().endswith('.tar.bz2') or file.lower().endswith('.tbz2'):
        if not os.path.isdir(temp + os.path.sep + name):
            os.mkdir(temp + os.path.sep + name)
        doShell('tar -xjvf %s -C %s%s' % (temp + os.path.sep + file, temp + os.path.sep + name, os.path.sep))
    setup = findSetup(temp + os.path.sep + name)
    #if os.path.isfile('setup.py'):
    if not setup:
        print 'no setup.py was found'
        sys.exit(1)
    else:
        print 'found setup.py in %s' % setup
        doSetup(setup)
    os.chdir(old)

def interactiveInstall(url):
    print 'found url: %s' % url
    choice = 'x'
    while choice not in ['y','n','']:
        echo('do you want me to install it? [Yn]:')
        choice = sys.stdin.readline().strip().lower()
    if choice == 'n':
        print 'aborting'
        sys.exit(1)
    else:
        doInstall(url)

def checkOrInstallPy(lib, url):
    echo('checking for %s ... ' % lib)
    try:
        __import__(lib)
        print 'ok'
    except ImportError, e:
        print 'not found'
        interactiveInstall(url)

def checkOrInstall(distro, lib):
    echo('checking for %s ... ' % lib)
    try:
        __import__(lib)
        print 'ok'
    except ImportError, e:
        print 'not found'
        if distro == 'archlinux' and PACKAGES[lib].has_key('pac'):
            installPacman(PACKAGES[lib]['pac'])
        elif distro == 'centos' and PACKAGES[lib].has_key('rpm'):
            installRPM(PACKAGES[lib]['rpm'])
        elif distro == 'debian' and PACKAGES[lib].has_key('deb'):
            installDeb(PACKAGES[lib]['deb'])
        elif PACKAGES[lib].has_key('src'):
            interactiveInstall(PACKAGES[lib]['src'])

def checkPyVersion():
    echo('checking for python version ... %d.%d.%d ' % sys.version_info[0:3])
    if sys.version_info < (2,4,1):
        print 'you need at least python 2.4.1'
        sys.exit(1)
    else:
        print 'ok'

def findDistro():
    if os.path.isfile('/etc/arch-release'):
        return 'archlinux'
    if os.path.isfile('/etc/redhat-release'):
        return 'redhat'
    if os.path.isfile('/etc/debian_version'):
        return 'debian'
    return None

if not os.path.isdir('tmp'):
    os.mkdir('tmp')

#
# MAIN
#

if __name__ == '__main__':
    print 'running configure for DDB %s' % DDB_VERSION
    checkPyVersion()
    #checkOrInstallPy('twisted.core',    'http://tmrc.mit.edu/mirror/twisted/Twisted/2.4/Twisted-2.4.0.tar.bz2')
    #checkOrInstallPy('twisted.names',  'http://tmrc.mit.edu/mirror/twisted/Names/0.2/TwistedNames-0.2.0.tar.bz2')
    #checkOrInstallPy('twisted.conch',  'http://tmrc.mit.edu/mirror/twisted/Conch/0.6/TwistedConch-0.6.0.tar.bz2')
    #checkOrInstallPy('twisted.web',    'http://tmrc.mit.edu/mirror/twisted/Web/0.5/TwistedWeb-0.5.0.tar.bz2')
    #checkOrInstallPy('twisted.words',  'http://tmrc.mit.edu/mirror/twisted/Words/0.3/TwistedWords-0.3.0.tar.bz2')
    #checkOrInstallPy('feedparser',     'http://%s.dl.sourceforge.net/feedparser/feedparser-4.1.zip' % SF_MIRROR)

    distro = None # findDistro()
    #if not distro:
    #    print 'WARNING: could not auto determine your distribution'
    #checkOrInstallPyDist(distro, 'pysqlite2')
    for package in PACKAGES.keys():
        checkOrInstall(distro, package)

    print 'you might want to clean out tmp/ a bit now'

# vim:ts=4:sw=4:et:
